import random
import time
import math

move_file_path = r"G:\tdma-projects\omnet-tdma-main\tdma\simulations\mymotion.movements"
num_hosts = 5
min_x, min_y, max_x, max_y = 100, 0, 600, 400
position_change = 0.5  # 节点目标位置改变概率
offline_rate = 0.01  # 节点离线概率
# 待在上一次位置的概率 = 1 - offline_rate - position_change
register_rate = 0.99  # 上线成功概率
change_interval = 1  # 节点目标位置改变间隔，单位为秒，40ms = 0.04s
max_move_radius = 50  # 节点一次移动的最大半径


class Node:
    """节点类"""

    MIN_OFFLINE_INTERVAL = 20  # 定义类变量"最短上线时间间隔"，单位为秒，超过该时间后节点有概率上线
    MAX_ONLINE_INTERVAL = 30  # 定义"最长在线时间间隔"，单位为秒，超过该时间后节点有概率下线

    def __init__(self, nid, position, status='online'):
        self.id = nid
        self.position = position  # (x,y)
        self.status = status
        self.last_move_time = 0
        self.last_change_time = 0
        self.last_offline_time = 0
        self.last_online_time = 0
        self.max_retry = 1000  # 随机位置生成最大尝试次数

    def move(self, target_position):
        self.position = target_position
        self.last_move_time = time.time()
        # 记录两个时间之间相差的秒数

    # 节点注册上线
    def register(self):
        self.status = 'online'
        self.last_online_time = time.time()

    # 节点离线
    def offline(self):
        self.position = (0, 0)
        self.status = 'offline'
        self.last_offline_time = time.time()

    def update_position(self):
        new_pos = generate_random_position_in_circle(self.position, max_move_radius)
        try_time = 0
        while not check_boundary(new_pos, min_x, min_y, max_x, max_y) and try_time < self.max_retry:  # TODO 定义最大尝试次数
            new_pos = generate_random_position_in_circle(self.position, max_move_radius)
            try_time += 1
        if check_boundary(new_pos, min_x, min_y, max_x, max_y):  # 超过最大尝试次数后仍在不在边界内，则使用随机位置
            self.move(new_pos)  # 更新节点的新位置
        else:
            self.move(generate_random_position(min_x, min_y, max_x, max_y))


def generate_random_nodes(num_nodes=3, min_x=0, min_y=0, max_x=600, max_y=400):
    nodes = []
    for i in range(num_nodes):
        nodes.append(
            Node(
                nid=i,
                position=generate_random_position(min_x, min_y, max_x, max_y),
                status='online'
            )
        )
    return nodes


def generate_random_position(min_x=0, min_y=0, max_x=600, max_y=400):
    x = random.randint(min_x, max_x - 1)
    y = random.randint(min_y, max_y - 1)
    return x, y


def generate_random_position_in_circle(node_position, radius):
    x_center, y_center = node_position
    # 随机生成一个位于[0, 2π]范围内的角度
    angle = random.uniform(0, 2 * math.pi)

    # 随机生成一个位于[0, r]范围内的半径（这里不需要考虑负半径，因为我们只关心圆内点）
    r_random = random.uniform(0, radius)

    # 根据极坐标转换为笛卡尔坐标
    new_x = round(x_center + r_random * math.cos(angle))
    new_y = round(y_center + r_random * math.sin(angle))

    return int(new_x), int(new_y)  # 直接返回落在圆内的随机位置


def check_boundary(position, min_x, min_y, max_x, max_y):
    x, y = position
    return min_x <= x <= max_x and min_y <= y <= max_y


def update_node_positions(file_path):
    # 获取初始节点
    nodes = generate_random_nodes(num_hosts, min_x, min_y, max_x, max_y)
    run_rounds = 1  # 运行的回合数
    while True:
        # 每隔500毫秒更新一次节点位置
        time.sleep(change_interval)
        print("#" * 25, run_rounds, "#" * 25)
        run_rounds += 1

        # 重写位置文件
        with open(file_path, 'w') as file:
            for node in nodes:
                line = f"{node.id} {node.position[0]} {node.position[1]}\n"
                print("line", line)
                file.write(line)
                # print(f"node {node_id} is at {x}, {y}")

        # 更新节点的位置
        for node in nodes:
            if node.status == 'offline':
                # 随机概率上线
                if time.time() - node.last_offline_time > Node.MIN_OFFLINE_INTERVAL and random.random() < register_rate:
                    node.register()
                    node.update_position()  # 更新位置
                    print(f"node {node.id} is registered online, position is {node.position}")
                continue

            action = random.choices(['move', 'offline', 'stay'],
                                    weights=[position_change, offline_rate, 1 - offline_rate - position_change], k=1)[0]
            # print(f"node {node_id} action is {action}")
            # 每个节点一轮有概率改变目标位置
            if action == 'move':
                print(f"node {node.id} changed direction, new position is {node.position}")
                node.update_position()
            elif action == 'offline':  # 概率离线
                if time.time() - node.last_offline_time > Node.MAX_ONLINE_INTERVAL:  # 节点在线时长超过最大在线时间间隔时，离线
                    print(f"node {node.id} is offline")
                    node.offline()
                else:
                    print(f"node {node.id} changed direction, new position is {node.position}")
                    node.update_position()
            else:
                print(f"node {node.id} stays at {node.position}")


if __name__ == '__main__':
    # 调用函数开始更新节点位置
    update_node_positions(move_file_path)

    # last_offline_time = time.time()
    # while True:
    #     time.sleep(1)
    #     interval = time.time() - last_offline_time
    #     print(f"interval is {interval}")
    #     if interval > 10:
    #         print("offline")

    # try_time = 0
    # position = generate_random_position(min_x, min_y, max_x, max_y)
    # new_pos = generate_random_position_in_circle(position, 10)
    # start = time.time()
    # while try_time < 1000:  # 定义最大尝试次数，1000次约用时0.001s
    #     new_pos = generate_random_position_in_circle(position, max_move_radius)
    #     try_time += 1
    # end = time.time()
    # print(end - start)
